package com.huadao.cart_ccs.netty;

import android.util.Log;
import android.widget.Toast;

import com.huadao.cart_ccs.Event.ConsoleEvent;
import com.huadao.cart_ccs.common.ByteUtils;
import com.huadao.cart_ccs.common.Constants;
import com.huadao.cart_ccs.main.CartApplication;
import com.huadao.cart_ccs.modle.LogModle;

import org.greenrobot.eventbus.EventBus;

import java.util.Date;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;

import static com.serenegiant.utils.UIThreadHelper.runOnUiThread;

public class NettyClient {
    private static final String TAG = "NettyClient";
    private static NettyClient nettyClient = new NettyClient();

    private EventLoopGroup group;

    private NettyListener listener;

    private Channel channel;

    private boolean isConnect = false;

    private int reconnectNum = Integer.MAX_VALUE;

    private long reconnectIntervalTime = 5000;

    private LogModle logModle=new LogModle();

    //100毫秒延迟
    private long delay=100;
    //上次发送时间
    private long lastSendTime;

    public static NettyClient getInstance(){
        return nettyClient;
    }

    public NettyClient connect() {
        if (!isConnect) {
            group = new NioEventLoopGroup();
            Bootstrap bootstrap = new Bootstrap().group(group)
                    .option(ChannelOption.SO_KEEPALIVE,true)
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS,5000)
                    .channel(NioSocketChannel.class)
                    .handler(new NettyClientInitializer(listener));

            try {
                logModle.recordOperation(Constants.socket,Constants.socketConnect);
                bootstrap.connect(Constants.HOST, Constants.TCP_PORT).addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture channelFuture) throws Exception {
                        if (channelFuture.isSuccess()) {
                            isConnect = true;
                            channel = channelFuture.channel();
                            logModle.recordOperation(Constants.socket,Constants.socketConnectSucc);
                        } else {
                            isConnect = false;
                            logModle.recordOperation(Constants.socket,Constants.socketConnectFail);
                        }
                    }
                }).sync();
            } catch (Exception e) {
                e.printStackTrace();
                listener.onServrStatusConnectChanged(NettyListener.STATUS_CONNECT_ERROR);
                logModle.recordOperation(Constants.socket,Constants.socketConnectException+e.getLocalizedMessage());
                reconnect();
            }
        }
        return this;
    }

    public void disconnect() {
        group.shutdownGracefully();
    }

    public void reconnect() {
        if(reconnectNum >0 && !isConnect){
            reconnectNum--;
            try {
                Thread.sleep(reconnectIntervalTime);
            } catch (InterruptedException e) {}
            Log.d(TAG,"重新连接");
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(CartApplication.getInstance(),"socket正在重新连接",Toast.LENGTH_SHORT).show();
                }
            });
            disconnect();
            connect();
        }else{
            disconnect();
        }
    }

    public synchronized boolean sendMsgToServer(final byte[] data, ChannelFutureListener listener) {
        boolean flag = channel != null && isConnect;

        if (flag) {
            long now=new Date().getTime();
            long gap=now-lastSendTime;
            if(gap<delay){
                try {
                    Log.i(TAG,"sleep: "+(delay-gap));
                    Thread.sleep(delay-gap);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            lastSendTime=new Date().getTime();

            ByteBuf buf = Unpooled.copiedBuffer(data);
//            channel.writeAndFlush(buf).addListener(listener);
            channel.writeAndFlush(buf).addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    String string= ByteUtils.getHexByte(data,0,data.length);
                    Log.i(TAG,"serialPortRequest: "+string+"  time: "+lastSendTime);
                    EventBus.getDefault().post(new ConsoleEvent(string,ConsoleEvent.TYPE_REQUEST,new Date()));
                    logModle.recordOperation(Constants.socket_request,string);
                }
            });

        }
        return flag;
    }

//    public synchronized boolean sendMsgToServer(final Protocol protocol, ChannelFutureListener listener) {
//        boolean flag = channel != null && isConnect;
//
//        if (flag) {
//            long now=new Date().getTime();
//            long gap=now-lastSendTime;
//            if(gap<delay){
//                try {
//                    Log.i(TAG,"sleep: "+(delay-gap));
//                    Thread.sleep(delay-gap);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//            }
//
//            lastSendTime=new Date().getTime();
//
//            ByteBuf buf = Unpooled.copiedBuffer(protocol.getParams());
////            channel.writeAndFlush(buf).addListener(listener);
//            channel.writeAndFlush(buf).addListener(new ChannelFutureListener() {
//                @Override
//                public void operationComplete(ChannelFuture future) throws Exception {
//                    if(future.isSuccess()) {
//                        String string = protocol.toString();
//                        Log.i(TAG, "serialPortRequest: " + string + "  time: " + lastSendTime);
//                        EventBus.getDefault().post(new ConsoleEvent(string, ConsoleEvent.TYPE_REQUEST));
////                        logModle.recordOperation(Constants.socket_request, string);
//                        logModle.recordOperation(protocol);
//                    }
//                }
//            });
//        }
//        return flag;
//    }

    public void setReconnectNum(int reconnectNum) {
        this.reconnectNum = reconnectNum;
    }

    public void setReconnectIntervalTime(long reconnectIntervalTime) {
        this.reconnectIntervalTime = reconnectIntervalTime;
    }

    public boolean getConnectStatus(){
        return isConnect;
    }

    public void setConnectStatus(boolean status){
        this.isConnect = status;
    }

    public void setListener(NettyListener listener) {
        this.listener = listener;
    }
}
